home *** CD-ROM | disk | FTP | other *** search
/ GameStar 2004 April / Gamestar_61_2004-04_dvdb.iso / DVDStar / Editace / hltp.exe / {app} / Source Code / Zoners Half-Life Tools / template / ReferenceObject.h < prev    next >
C/C++ Source or Header  |  2001-04-18  |  7KB  |  233 lines

  1. // Copyright (C) 2000  Sean Cavanaugh
  2. // This file is licensed under the terms of the Lesser GNU Public License
  3. // (see LPGL.txt, or http://www.gnu.org/copyleft/lesser.txt)
  4.  
  5. #if !defined(AFX_REFERENCEOBJECT_H__BAEBCE9D_CD68_40AF_8A54_B23A0D14E807__INCLUDED_)
  6. #define AFX_REFERENCEOBJECT_H__BAEBCE9D_CD68_40AF_8A54_B23A0D14E807__INCLUDED_
  7.  
  8. #if _MSC_VER > 1000
  9. #pragma once
  10. #endif // _MSC_VER > 1000
  11.  
  12. #ifdef WIN32
  13. #define WIN32_LEAN_AND_MEAN
  14. #include "windows.h"
  15. #endif
  16. #include "assert.h"
  17. #include "limits.h"
  18.  
  19. #include "ReferenceCounter.h"
  20.  
  21. template<class HEADER_T, class DATA_T>
  22. class ReferenceObjectBlock
  23. {
  24. public:
  25.     DATA_T*            pData;            // User defined data block
  26.     mutable ReferenceCounter    ReferenceCount;
  27.     unsigned int    AllocLength;    // Current size of array, in T sized units.  if AllocLength = 0, pData is const and needs CopyOnWrite
  28.     HEADER_T        Header;            // User defined header block (must be safe to copy with operator=)
  29. };
  30.  
  31.  
  32.  
  33. /*!
  34.   \author  Sean Cavanaugh
  35.   \email   sean@dimensionalrift.com
  36.   \cvsauthor $Author: sean $
  37.   \date    $Date: 2000/09/11 20:28:24 $
  38.   \version $Revision: 1.1 $ 
  39.   \brief   ReferenceObject is a template class designed to be used a base class for pass-by-reference objects, to that things such as returning objects up the stack efficiently are possible.
  40.   \bug     EVERY non const function needs its very first operation to be CopyForWrite()
  41.   \bug     EVERY derived class should define its operator=() to call the ReferenceObject base class version (notice this operator is protected,)
  42.   \bug     HEADER_T will probably need an operator=() defined for all but the most trivial types
  43.   \bug     Store objects or simple data types, NO POINTERS (use ReferencePtrObject for that) (they will leak like mad)
  44.  
  45. */
  46.  
  47.  
  48.  
  49. template<class HEADER_T, class DATA_T>
  50. class ReferenceObject  
  51. {
  52. public:
  53.     ReferenceObject();
  54.     ReferenceObject(unsigned int size);
  55.     ReferenceObject(const ReferenceObject<HEADER_T,DATA_T>& other);
  56.     virtual ~ReferenceObject();
  57.  
  58. public:
  59.     HEADER_T& getHeader();
  60.     DATA_T* getData();
  61.  
  62.     ReferenceObject<HEADER_T,DATA_T>& operator=(const ReferenceObject<HEADER_T,DATA_T>& other);
  63.  
  64. protected:
  65.     void AllocBlock(unsigned int size);    // Allocate Header+Data Block (size in T units)
  66.     void AllocHeader();            // Allocate Header Block
  67.     void AllocData(unsigned int size);    // Alocate Data Block (size in T units)
  68.  
  69.     virtual void Release();                // Releases a reference count (possibly freeing memory)
  70.     virtual void InitHeader();            // User defined Header Initialization function
  71.     virtual void FreeHeader();            // User defined Header destructor function
  72.     virtual void CopyForWrite();                    // Make unique copy for writing, must first instruction in all non const-functions in derived classes
  73.     virtual void CopyForWrite(unsigned int size);    // same as CopyForWrite() except takes a resize parameter
  74.  
  75.     ReferenceObjectBlock<HEADER_T,DATA_T>* m_pData;
  76. };
  77.  
  78.  
  79. template<class HEADER_T, class DATA_T>
  80. ReferenceObject<HEADER_T,DATA_T>::ReferenceObject()
  81. {
  82.     m_pData = NULL;
  83.     AllocHeader();
  84.     InitHeader();
  85. }
  86.  
  87. template<class HEADER_T, class DATA_T>
  88. ReferenceObject<HEADER_T,DATA_T>::ReferenceObject(unsigned int size)
  89. {
  90.     m_pData = NULL;
  91.     AllocBlock(size);
  92. }
  93.  
  94. template<class HEADER_T, class DATA_T>
  95. ReferenceObject<HEADER_T,DATA_T>::ReferenceObject(const ReferenceObject<HEADER_T,DATA_T>& other)
  96. {
  97.     m_pData = other.m_pData;
  98.     m_pData->ReferenceCount++;
  99. }
  100.  
  101. template<class HEADER_T, class DATA_T>
  102. ReferenceObject<HEADER_T,DATA_T>::~ReferenceObject()
  103. {
  104.     Release();
  105. }
  106.  
  107. template<class HEADER_T, class DATA_T>
  108. ReferenceObject<HEADER_T,DATA_T>& ReferenceObject<HEADER_T,DATA_T>::operator=(const ReferenceObject<HEADER_T,DATA_T>& other)
  109. {
  110.     if (m_pData != other.m_pData)
  111.     {
  112.         Release();
  113.         m_pData = other.m_pData;
  114.         m_pData->ReferenceCount++;
  115.     }
  116.     return *this;
  117. }
  118.  
  119. template<class HEADER_T, class DATA_T>
  120. void ReferenceObject<HEADER_T,DATA_T>::Release()
  121. {
  122.     assert(m_pData != NULL);
  123.     if (m_pData->ReferenceCount.dec() <= 0)
  124.     {
  125.         FreeHeader();
  126.         delete[] m_pData->pData;
  127.         delete m_pData;
  128.         m_pData = NULL;
  129.     }
  130. }
  131.  
  132. template<class HEADER_T, class DATA_T>
  133. void ReferenceObject<HEADER_T,DATA_T>::AllocBlock(unsigned int size)
  134. {
  135.     AllocHeader();
  136.     AllocData(size);
  137.     InitHeader();    // Initialize user defined header
  138. }
  139.  
  140. template<class HEADER_T, class DATA_T>
  141. void ReferenceObject<HEADER_T,DATA_T>::AllocHeader()
  142. {
  143.     m_pData = new ReferenceObjectBlock<HEADER_T,DATA_T>;
  144.  
  145.     m_pData->ReferenceCount = 1;
  146.     m_pData->pData = NULL;
  147.     m_pData->AllocLength = 0;
  148. }
  149.  
  150. template<class HEADER_T, class DATA_T>
  151. void ReferenceObject<HEADER_T,DATA_T>::AllocData(unsigned int size)
  152. {
  153.     assert(m_pData != NULL);
  154.     assert((size * sizeof(DATA_T)) < INT_MAX);
  155.  
  156.     if (size)
  157.     {
  158.         m_pData->pData = new DATA_T[size];
  159.     }
  160.     else
  161.     {
  162.         m_pData->pData = NULL;
  163.     }
  164.     m_pData->AllocLength = size;
  165. }
  166.  
  167. template<class HEADER_T, class DATA_T>
  168. void ReferenceObject<HEADER_T,DATA_T>::InitHeader()
  169. {
  170.     // NOTE: Derive this function to initialize the Header object(s)
  171. }
  172.  
  173. template<class HEADER_T, class DATA_T>
  174. void ReferenceObject<HEADER_T,DATA_T>::FreeHeader()
  175. {
  176.     // NOTE: Derive this function to clean up the Header object(s)
  177. }
  178.  
  179. template<class HEADER_T, class DATA_T>
  180. void ReferenceObject<HEADER_T,DATA_T>::CopyForWrite()
  181. {
  182.     CopyForWrite(m_pData->AllocLength);
  183. }
  184.  
  185. template<class HEADER_T, class DATA_T>
  186. void ReferenceObject<HEADER_T,DATA_T>::CopyForWrite(unsigned int size)
  187. {
  188.     unsigned int oldsize = m_pData->AllocLength;
  189.  
  190.     if (size)
  191.     {
  192.         if ((m_pData->ReferenceCount > 1) || (size != oldsize))
  193.         {
  194.             ReferenceObjectBlock<HEADER_T,DATA_T>* pTmp = m_pData;
  195.             AllocBlock(size);
  196.             m_pData->Header = pTmp->Header;
  197.             unsigned int sizetocopy = min(size,oldsize);
  198.             // memcpy(m_pData->pData, pTmp->pData, min(size,oldsize) * sizeof(DATA_T));  // memcpy not safe for objects
  199.             for (unsigned int x=0;x<sizetocopy;x++)
  200.             {
  201.                 m_pData->pData[x] = pTmp->pData[x];
  202.             }
  203.             if (pTmp->ReferenceCount.dec() <= 0)
  204.             {
  205.                 delete[] pTmp->pData;
  206.                 delete pTmp;
  207.             }
  208.         }
  209.     }
  210.     else    // Replace reference to a null object (since size is zero)
  211.     {
  212.         Release();
  213.         AllocHeader();
  214.         InitHeader();
  215.     }
  216. }
  217.  
  218. template<class HEADER_T, class DATA_T>
  219. HEADER_T& ReferenceObject<HEADER_T,DATA_T>::getHeader()
  220. {
  221.     CopyForWrite();
  222.     return m_pData->Header;
  223. }
  224.  
  225. template<class HEADER_T, class DATA_T>
  226. DATA_T* ReferenceObject<HEADER_T,DATA_T>::getData()
  227. {
  228.     CopyForWrite();
  229.     return m_pData->pData;
  230. }
  231.  
  232. #endif // !defined(AFX_REFERENCEOBJECT_H__BAEBCE9D_CD68_40AF_8A54_B23A0D14E807__INCLUDED_)
  233.